home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / JFC.bin / BasicDirectoryModel.java < prev    next >
Text File  |  1998-06-30  |  9KB  |  346 lines

  1. /*
  2.  * @(#)BasicDirectoryModel.java    1.6 98/04/14
  3.  * 
  4.  * Copyright (c) 1997,1998 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  */
  20.  
  21. package com.sun.java.swing.plaf.basic;
  22.  
  23. import java.io.File;
  24. import java.util.Vector;
  25. import com.sun.java.swing.*;
  26. import com.sun.java.swing.preview.filechooser.*;
  27. import com.sun.java.swing.preview.*;
  28. import com.sun.java.swing.event.*;
  29. import java.beans.*;
  30.  
  31.  
  32. /**
  33.  * Basic implementation of a file list.
  34.  *
  35.  * @version %i% %g%
  36.  * @author Jeff Dinkins
  37.  */
  38. class BasicDirectoryModel extends AbstractListModel implements PropertyChangeListener {
  39.     
  40.     private JFileChooser filechooser = null;
  41.     private Vector fileCache = null;
  42.     private LoadFilesThread loadThread = null;
  43.     private Vector files = null;
  44.     private Vector directories = null;
  45.     
  46.     BasicDirectoryModel(JFileChooser filechooser) {
  47.     this.filechooser = filechooser;
  48.     validateFileCache();
  49.     }
  50.  
  51.     public void propertyChange(PropertyChangeEvent e) {
  52.     String prop = e.getPropertyName();
  53.     if(prop == JFileChooser.DIRECTORY_CHANGED_PROPERTY ||
  54.        prop == JFileChooser.FILE_VIEW_CHANGED_PROPERTY ||
  55.        prop == JFileChooser.FILE_FILTER_CHANGED_PROPERTY ||
  56.        prop == JFileChooser.FILE_HIDING_CHANGED_PROPERTY ||
  57.        prop == JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY) {
  58.         invalidateFileCache();
  59.         validateFileCache();
  60.     }
  61.     }
  62.  
  63.     public void invalidateFileCache() {
  64.     files = null;
  65.     directories = null;
  66.     fileCache = null;
  67.     }
  68.  
  69.     public Vector getDirectories() {
  70.     if(directories != null) {
  71.         return directories;
  72.     }
  73.     Vector fls = getFiles();
  74.     return directories;
  75.     }
  76.  
  77.     public Vector getFiles() {
  78.     if(files != null) {
  79.         return files;
  80.     }
  81.     files = new Vector();
  82.     directories = new Vector();
  83.     directories.addElement(filechooser.getFileSystemView().createFileObject(
  84.         filechooser.getCurrentDirectory(), "..")
  85.     );
  86.  
  87.     for(int i = 0; i < fileCache.size(); i++) {
  88.         File f = (File) fileCache.elementAt(i);
  89.         if(filechooser.isTraversable(f)) {
  90.         directories.addElement(f);
  91.         } else {
  92.         files.addElement(f);
  93.         }
  94.     }
  95.     return files;
  96.     }
  97.  
  98.     public void validateFileCache() {
  99.     File currentDirectory = filechooser.getCurrentDirectory();
  100.     
  101.     if(currentDirectory == null) {
  102.         invalidateFileCache();
  103.         return;
  104.     }
  105.  
  106.     // PENDING(jeff) pick the size more sensibly
  107.     fileCache = new Vector(50);
  108.     
  109.     // PENDING(jeff) interrupt
  110.     if(loadThread != null) {
  111.         // interrupt
  112.         loadThread.interrupt();
  113.     }
  114.     loadThread = new LoadFilesThread(currentDirectory);
  115.     loadThread.start();
  116.     }
  117.  
  118.     // PENDING(jeff) - this is inefficient - should sent out
  119.     // incremental adjustment values instead of saying that the
  120.     // whole list has changed.
  121.     public void fireContentsChanged() {
  122.     // System.out.println("BasicDirectoryModel: firecontentschanged");
  123.     files = null;
  124.     directories = null;
  125.     fireContentsChanged(this, 0, fileCache.size()-1);
  126.     }
  127.     
  128.     public int getSize() {
  129.     if(fileCache != null) {
  130.         return fileCache.size();
  131.     } else {
  132.         return 0;
  133.     }
  134.     }
  135.  
  136.     public boolean contains(Object o) {
  137.     if(fileCache != null) {
  138.         return fileCache.contains(o);
  139.     } else {
  140.         return false;
  141.     }
  142.     }
  143.  
  144.     public int indexOf(Object o) {
  145.     if(fileCache != null) {
  146.         return fileCache.indexOf(o);
  147.     } else {
  148.         return 0;
  149.     }
  150.     }
  151.     
  152.     public Object getElementAt(int index) {
  153.     if(fileCache != null) {
  154.         return fileCache.elementAt(index);
  155.     } else {
  156.         return null;
  157.     }
  158.     }
  159.     
  160.     // PENDING(jeff) - implement
  161.     public void intervalAdded(ListDataEvent e) {
  162.     }
  163.     
  164.     // PENDING(jeff) - implement
  165.     public void intervalRemoved(ListDataEvent e) {
  166.     }
  167.     
  168.     protected void sort(Vector v){
  169.     quickSort(v, 0, v.size()-1);
  170.     }
  171.     
  172.     
  173.     // Liberated from the 1.1 SortDemo
  174.     // 
  175.     // This is a generic version of C.A.R Hoare's Quick Sort
  176.     // algorithm.  This will handle arrays that are already
  177.     // sorted, and arrays with duplicate keys.<BR>
  178.     //
  179.     // If you think of a one dimensional array as going from
  180.     // the lowest index on the left to the highest index on the right
  181.     // then the parameters to this function are lowest index or
  182.     // left and highest index or right.  The first time you call
  183.     // this function it will be with the parameters 0, a.length - 1.
  184.     //
  185.     // @param a       an integer array
  186.     // @param lo0     left boundary of array partition
  187.     // @param hi0     right boundary of array partition
  188.     private void quickSort(Vector v, int lo0, int hi0) {
  189.     int lo = lo0;
  190.     int hi = hi0;
  191.     File mid;
  192.     
  193.     if (hi0 > lo0) {
  194.         // Arbitrarily establishing partition element as the midpoint of
  195.         // the array.
  196.         mid = (File) v.elementAt((lo0 + hi0) / 2);
  197.         
  198.         // loop through the array until indices cross
  199.         while(lo <= hi) {
  200.         // find the first element that is greater than or equal to
  201.         // the partition element starting from the left Index.
  202.         //
  203.         // Nasty to have to cast here. Would it be quicker
  204.         // to copy the vectors into arrays and sort the arrays?
  205.         while((lo < hi0) && lt((File)v.elementAt(lo), mid)) {
  206.             ++lo;
  207.         }
  208.             
  209.         // find an element that is smaller than or equal to
  210.         // the partition element starting from the right Index.
  211.         while((hi > lo0) && lt(mid, (File)v.elementAt(hi))) {
  212.             --hi;
  213.         }
  214.             
  215.         // if the indexes have not crossed, swap
  216.         if(lo <= hi) {
  217.             swap(v, lo, hi);
  218.             ++lo;
  219.             --hi;
  220.         }
  221.         }
  222.  
  223.         
  224.         // If the right index has not reached the left side of array
  225.         // must now sort the left partition.
  226.         if(lo0 < hi) {
  227.         quickSort(v, lo0, hi);
  228.         }
  229.         
  230.         // If the left index has not reached the right side of array
  231.         // must now sort the right partition.
  232.         if(lo < hi0) {
  233.         quickSort(v, lo, hi0);
  234.         }
  235.         
  236.     }
  237.     }
  238.  
  239.     private void swap(Vector a, int i, int j) {
  240.     Object T = a.elementAt(i);
  241.     a.setElementAt(a.elementAt(j), i);
  242.     a.setElementAt(T, j);
  243.     }
  244.  
  245.     protected boolean lt(File a, File b) {
  246.     return a.getName().compareTo(b.getName()) < 0;
  247.     }
  248.     
  249.  
  250.     class LoadFilesThread extends Thread {
  251.     File currentDirectory = null;
  252.  
  253.     public LoadFilesThread(File currentDirectory) {
  254.         super("Basic L&F File Loading Thread");
  255.         this.currentDirectory = currentDirectory;
  256.     }
  257.  
  258.     public void run() {
  259.         Vector runnables = new Vector(10);
  260.         FileSystemView fileSystem = filechooser.getFileSystemView();
  261.         
  262.         File[] list = fileSystem.getFiles(currentDirectory, filechooser.isFileHidingEnabled());
  263.         
  264.         Vector acceptsList = new Vector();
  265.         
  266.         // run through the file list, add directories and selectable files to fileCache 
  267.         for (int i = 0; i < list.length; i++) {
  268.         if(filechooser.accept(list[i])) {
  269.             acceptsList.addElement(list[i]);
  270.         } 
  271.         }
  272.         
  273.         // First sort alphabetically by filename
  274.         sort(acceptsList);
  275.         
  276.         Vector directories = new Vector(10);
  277.         Vector files = new Vector();
  278.         // run through list grabbing directories in chunks of ten
  279.         for(int i = 0; i < acceptsList.size(); i++) {
  280.         File f = (File) acceptsList.elementAt(i);
  281.         boolean isTraversable = filechooser.isTraversable(f);
  282.         if(isTraversable) {
  283.             directories.addElement(f);
  284.         } else if(!isTraversable && filechooser.isFileSelectionEnabled()) {
  285.             files.addElement(f);
  286.         }
  287.         if((directories.size() == 10) || (i == acceptsList.size()-1)) {
  288.             DoChangeContents runnable = new DoChangeContents(directories);
  289.             runnables.addElement(runnable);
  290.             SwingUtilities.invokeLater(runnable);
  291.             directories = new Vector(10);
  292.         }
  293.         if(isInterrupted()) {
  294.             // interrupted, cancel all runnables
  295.             cancelRunnables(runnables);
  296.             return;
  297.         }
  298.         }
  299.         // PENDING(jeff) - run through the files in blocks instead of
  300.         // sending them along as one big chunk
  301.         DoChangeContents runnable = new DoChangeContents(files);
  302.         runnables.addElement(runnable);
  303.         SwingUtilities.invokeLater(runnable);
  304.         if(isInterrupted()) {
  305.         // interrupted, blow out
  306.         cancelRunnables(runnables);
  307.         return;
  308.         }
  309.     }
  310.     
  311.     public void cancelRunnables(Vector runnables) {
  312.         for(int i = 0; i < runnables.size(); i++) {
  313.         ((DoChangeContents)runnables.elementAt(i)).cancel();
  314.         }
  315.     }
  316.     }
  317.     
  318.     class DoChangeContents implements Runnable {
  319.     private Vector files;
  320.     private boolean doFire = true;
  321.     private Object lock = new Object();
  322.  
  323.     public DoChangeContents(Vector files) {
  324.         this.files = files;
  325.     }
  326.  
  327.     synchronized void cancel() {
  328.         synchronized(lock) {
  329.         doFire = false;
  330.         }
  331.     }
  332.  
  333.     public void run() {
  334.         synchronized(lock) {
  335.         if(doFire) {
  336.             for(int i = 0; i < files.size(); i++) {
  337.             fileCache.addElement(files.elementAt(i));
  338.             }
  339.         }
  340.         fireContentsChanged();
  341.         }
  342.     }
  343.     }
  344. }
  345.  
  346.